package cheme.ProcessModel.Cmds;

import org.eclipse.gef.commands.Command;

import cheme.ProcessModel.IParent;
import cheme.ProcessModel.ProcessUnits.IProcessUnit;
import cheme.ProcessModel.ProcessUnits.ITerminal;
import cheme.ProcessModel.ProcessUnits.Streams.AbstractStream;
import cheme.ProcessModel.ProcessUnits.Streams.IStream;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.Tag;


public class DeleteStreamCmd extends Command
{
	private AbstractStream stream;
	
	private Tag tag;
	
	private IParent oldSourceParent;
	private IProcessUnit oldSource;

	private IParent oldSinkParent;
	private IProcessUnit oldSink;

	public DeleteStreamCmd(AbstractStream stream)
	{
		this.stream = stream;
	}
	
	public void execute()
	{
		/*
		 * this had better emit an interpretable event!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 */
		tag = stream.get(IStream.TAG_INDEX);
		stream.remove(tag);
		
		oldSource = stream.getSource();
		oldSink = stream.getSink();
		
		/*
		 * Note that detaching a stream from it's source unit is effectively removingit as a child.
		 * Likewise, attaching the stream to a source unit sets it up as the streams parent.
		 */
		stream.detachSource();
		stream.detachSink();
		
		/*
		 * Note that the following tests for stream set size == 0 need to come
		 * AFTER the detaching or else they will fail and terminals will not be 
		 * removed.
		 */
		
		if(oldSource instanceof ITerminal)
		{
			if(0 == oldSource.getOutStreams().size())
			{
				oldSourceParent = oldSource.getParent();
				oldSourceParent.remove(oldSource);
			}
		}
		
		if(oldSink instanceof ITerminal)
		{
			if(0 == oldSink.getInStreams().size())
			{
				oldSinkParent = oldSink.getParent();
				oldSinkParent.remove(oldSink);
			}
		}
	}

	private boolean previouslyRemovedSource()
	{
		return null != oldSourceParent;
	}
	
	private boolean previouslyRemovedSink()
	{
		return null != oldSinkParent;
	}

	@Override
	public void redo()
	{
		stream.remove(tag);
		
		stream.detachSource();
		stream.detachSink();
		
		/*
		 * Note that the following tests for stream set size == 0 need to come
		 * AFTER the detaching or else they will fail and terminals will not be 
		 * removed.
		 */
		
		if(oldSource instanceof ITerminal)
		{
			if(0 == oldSource.getOutStreams().size())
			{
				oldSourceParent = oldSource.getParent();
				oldSourceParent.remove(oldSource);
			}
		}

		if(oldSink instanceof ITerminal)
		{
			if(0 == oldSink.getInStreams().size())
			{
				oldSinkParent = oldSink.getParent();
				oldSinkParent.remove(oldSink);
			}
		}
	}
	
	public void undo()
	{
		/*
		 * Note that the following tests for stream set size == 0 need to come
		 * BEFORE the attaching or else they will fail and terminals will not be 
		 * re-added.
		 */
		
		if(previouslyRemovedSource())
		{
			oldSourceParent.add(oldSource);
		}
		
		if(previouslyRemovedSink())
		{
			oldSinkParent.add(oldSink);
		}

		stream.attachSource();
		stream.attachSink();
		
		stream.add(tag, IStream.TAG_INDEX);
	}
}
